/////////////////////////////////////////////////////
// File Name: afifo.v
// Author: zeping fan
// mail:   zpfan007@163.com
// Created Time: 2023年05月16日 星期二 21时43分53秒
/////////////////////////////////////////////////////

module afifo#(
    parameter   FIFO_DEPTH      = 16,
                DATA_WIDTH      = 8,
                DATA_FLOAT_OUT  = 1'b0// non-nil means the fisrt addr data will automatically float out,
                                       // nil value means that all data need a valid rd_en to output
)(
rstn_i,

wr_clk_i,
wr_en_i,
wr_data_i,
wr_full_o,
wr_cnt_o,

rd_clk_i,
rd_en_i,
rd_data_o,
rd_empty_o,
rd_cnt_o
);

parameter   PTR_WIDTH   = $clog2(FIFO_DEPTH);
//parameter   DATA_FLOAT_OUT  = 1'b0;       // non-nil means the fisrt addr data will automatically float out,
                                       // nil value means that all data need a valid rd_en to output


input                       rstn_i;
input                       wr_clk_i;
input                       wr_en_i;
input   [DATA_WIDTH-1:0]    wr_data_i;
output                      wr_full_o;
output  [PTR_WIDTH:0]       wr_cnt_o;

input                       rd_clk_i;
input                       rd_en_i;
output  [DATA_WIDTH-1:0]    rd_data_o;
output                      rd_empty_o;
output  [PTR_WIDTH:0]       rd_cnt_o;


                                                                       
wire    [PTR_WIDTH-1:0]     wr_addr;
wire    [PTR_WIDTH-1:0]     rd_addr;
wire    [PTR_WIDTH:0]       wptr_gray;
wire    [PTR_WIDTH:0]       wptr_bin;
wire    [PTR_WIDTH:0]       rptr_gray;
wire    [PTR_WIDTH:0]       rptr_bin;
wire    [PTR_WIDTH:0]       wp2rp_syn;
wire    [PTR_WIDTH:0]       rp2wp_syn;

wire                        wr_en;
wire                        rd_en;


assign  wr_en = wr_en_i && ~wr_full_o;

assign  rd_en = rd_en_i && ~rd_empty_o;

fifomem #(
    .DATA_WIDTH(DATA_WIDTH),
    .FIFO_DEPTH(FIFO_DEPTH),
    .DATA_FLOAT_OUT(DATA_FLOAT_OUT)
)
x_fifomem(
    .rstn_i(rstn_i),
    .wr_clk_i(wr_clk_i),
    .wr_en_i(wr_en),
    .wr_addr_i(wr_addr),
    .wr_data_i(wr_data_i),
    .rd_clk_i(rd_clk_i),
    .rd_en_i(rd_en),
    .rd_addr_i(rd_addr),
    .rd_data_o(rd_data_o)
);

rp2wp #(.PTR_WIDTH(PTR_WIDTH))
x_rp2wp(
    .wr_clk_i(wr_clk_i),
    .rstn_i(rstn_i),
    .rptr_gray_i(rptr_gray),
    .rp2wp_gray_o(rp2wp_syn)
);

wp2rp #(.PTR_WIDTH(PTR_WIDTH))
x_wp2rp(
    .rd_clk_i(rd_clk_i),
    .rstn_i(rstn_i),
    .wptr_gray_i(wptr_gray),
    .wp2rp_gray_o(wp2rp_syn)
);

rptr_empty #(.PTR_WIDTH(PTR_WIDTH),
             .DATA_FLOAT_OUT(DATA_FLOAT_OUT)
)           
x_rptr_empty(
    .rd_clk_i(rd_clk_i),
    .rstn_i(rstn_i),
    .rd_en_i(rd_en_i),
    .wptr_gray_i(wp2rp_syn),   
    .rd_empty_o(rd_empty_o),
    .rd_addr_o(rd_addr),
    .rptr_gray_o(rptr_gray),
    .rptr_bin_o(rptr_bin)
);

wptr_full #(.PTR_WIDTH(PTR_WIDTH))
x_wptr_full(
    .wr_clk_i(wr_clk_i),
    .rstn_i(rstn_i),
    .wr_en_i(wr_en_i),
    .rptr_gray_i(rp2wp_syn),
    .wptr_gray_o(wptr_gray),
    .wr_addr_o(wr_addr),
    .wr_full_o(wr_full_o),
    .wptr_bin_o(wptr_bin)
);

wr_cnt #(.PTR_WIDTH(PTR_WIDTH))
x_wr_cnt(
  .rstn_i(rstn_i),

  .wr_clk_i(wr_clk_i),
  .wptr_bin_i(wptr_bin),
  .rp2wp_gray_i(rp2wp_syn),
  .wr_cnt_o(wr_cnt_o)

);

rd_cnt #(.PTR_WIDTH(PTR_WIDTH))
x_rd_cnt(
  .rstn_i(rstn_i),

  .rd_clk_i(rd_clk_i),
  .rptr_bin_i(rptr_bin),
  .wp2rp_gray_i(wp2rp_syn),
  .rd_cnt_o(rd_cnt_o)
);



endmodule
